#! /usr/bin/env python3

import argparse
import pandas
import sys

DEFAULT_SEPARATOR = ','

SUMMARY_TABLE_INDEX = 6
SUMMARY_FIRST_COL = 'Status Group'
SUMMARY_LAST_RUN_COL = '#'
SUMMARY_BASELINE_COL = '# (B)'
SUMMARY_REGRESSION_ROW = 'Performance Regressions'
SUMMARY_IMPROVEMENT_ROW = 'Performance Improvements'

EXEC_IMPROVEMENTS_COL = 'Performance Improvements - execution_time'
EXEC_REGRESSIONS_COL = 'Performance Regressions - execution_time'
EXEC_LAST_RUN_COL = 'Δ'
EXEC_BASELINE_COL = 'Δ (B)'

EXEC_TIME_TABLE_INDEX = -2
GEOMEAN_INDEX = -2

def get_summary_table(tables):
    """Obtain the summary table by the first column name.

    :param tables: all tables on the page
    :type tables: list
    :return: the summary table
    :rtype: class:'pandas.core.frame.DataFrame'
    """
    for i, table in enumerate(tables):
        if table.get(SUMMARY_FIRST_COL) is not None:
            if i == SUMMARY_TABLE_INDEX - 1:
                print('Warning: Machine info for the current LNT machine is absent',
                      file=sys.stderr)
            return table
    return None

def get_regression_index(table):
    """Get regressions row number for the summary table.

    :param table: the summary table
    :type table: class:'pandas.core.frame.DataFrame'
    :return: index of the row with the regressions number or None if it's not found
    :rtype: int
    """

    try:
        regression_num = table.get(SUMMARY_FIRST_COL).tolist().index(SUMMARY_REGRESSION_ROW)
    except ValueError:
        regression_num = None
    return regression_num

def get_improvement_index(table):
    """Get improvements row number for the summary table.

    :param table: the summary table
    :type table: class:'pandas.core.frame.DataFrame'
    :return: index of the row with the improvements number or None if it's not found
    :rtype: int
    """

    try:
        improvement_num = table.get(SUMMARY_FIRST_COL).tolist().index(SUMMARY_IMPROVEMENT_ROW)
    except ValueError:
        improvement_num = None
    return improvement_num

def get_table(tables, first_col, second_col):
    """Return table with the specified first column header and the second column header.
    If the required table is not found, return None.

    :param tables: all tables from which the function chooses a table to return
    :type tables: list
    :param first_col: the first column header
    :type first_col: str
    :param second_col: the second column header
    :return: chosen table
    :rtype: class:'pandas.core.frame.DataFrame'
    """

    for table in tables:
        if table.columns[0] == first_col and table.columns[1] == second_col:
            return table
    return None

if __name__ == '__main__':
    parser = argparse.ArgumentParser(
            description='Get information about regressions and improvements from an LNT report. '
                        'Return format for default separator: '
                        '"<regression_num>{0}<improvement_num>{0}<total_num>{0}'
                        '<max_regression>{0}<max_improvement>{0}<geomean>"'
                        .format(DEFAULT_SEPARATOR),
            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument('url', help='URL of the LNT report')
    parser.add_argument('-s', '--separator',
                        default=DEFAULT_SEPARATOR,
                        help='Output separator.')
    parser.add_argument('-b', '--baseline',
                        action='store_true',
                        help='Get regressions and improvements number for baseline. '
                             'By default script returns them for the previous run.')
    args = parser.parse_args()
    if args.baseline:
        col_header = SUMMARY_BASELINE_COL
    else:
        col_header = SUMMARY_LAST_RUN_COL

    tables = pandas.read_html(args.url)
    summary_table = get_summary_table(tables)
    exec_time_table = tables[EXEC_TIME_TABLE_INDEX]

    # Get performance regressions and improvements numbers.
    regr_index = get_regression_index(summary_table)
    impr_index = get_improvement_index(summary_table)
    # default_series is used when we try to get baseline info, but baseline is absent
    # in the LNT report.
    default_series = pandas.Series([0]*len(summary_table.index))
    regression_num = int(summary_table.get(col_header, default_series).get(regr_index, 0))
    improvement_num = int(summary_table.get(col_header, default_series).get(impr_index, 0))
    res_list = [str(regression_num), str(improvement_num)]
    res_list.append(str(len(exec_time_table.values)-2))

    # Get maximum regression and improvement.
    max_regr='0.0%'
    max_impr='-0.0%'
    second_col = EXEC_BASELINE_COL if args.baseline else EXEC_LAST_RUN_COL
    if regression_num > 0:
        regr_table = get_table(tables, EXEC_REGRESSIONS_COL, second_col)
        max_regr = regr_table.get(second_col)[0]
    if improvement_num > 0:
        impr_table = get_table(tables, EXEC_IMPROVEMENTS_COL, second_col)
        max_impr = impr_table.get(second_col)[0]
    res_list += [max_regr, max_impr]

    # Get geometric mean for execution time delta.
    res_list.append(exec_time_table.get('%').tolist()[GEOMEAN_INDEX])

    print(args.separator.join(res_list))
